package core;

import java.util.ArrayList;
import org.apache.log4j.Logger;

/**
 *
 * @author Sakis Vtdk <sakis.vtdk@gmail.com>
 */
public class ReverseChange
{

	public ReverseChange(ArrayList<Change> changes)
	{
		this._changes = changes;
		reverseChanges();

	}

	public ReverseChange(Change change)
	{
		this._changes.add(change);
		reverseChanges();
	}

	/**
	 * Starts the process of reversing the change
	 */
	private void reverseChanges()
	{
		for(Change change : this._changes)
		{
			Change reversedChange = new Change();

			//only some things are going to change, so lets clone the change:
			try
			{
				reversedChange = change.clone();
				reversedChange.setIsReverse(true);
			}
			catch(CloneNotSupportedException ex)
			{
				log.error("Cloning failed. Error returned was: "+ ex.getMessage());
			}

			//call the appropriate method based on the type of change
			if(change.getType().equals(Change.Type.CREATE.toString()))
			{
				reverseCreate(change, reversedChange);
			}
			else if(change.getType().equals(Change.Type.DELETE.toString()))
			{
				reverseDelete(change, reversedChange);
			}
			else
			{
				reverseUpdate(change, reversedChange);
			}
			
			//this._reversedChanges.add(reversedChange);
			this._reversedChanges.add(0, reversedChange);
		}

	}


	/**
	 * Reverses a change of type == CREATE
	 * 
	 * @param change The original change which is to be reversed
	 * @param reversedChange The reversed change
	 */
	private void reverseCreate(Change change, Change reversedChange)
	{
		//that's the easy one: if something was created, we delete it
		reversedChange.setType(Change.Type.DELETE);
		reversedChange.setName(change.getName());
	}

	/**
	 * Reverses a change of type == DELETE
	 * 
	 * @param change The original change which is to be reversed
	 * @param reversedChange The reversed change
	 */
	private void reverseDelete(Change change, Change reversedChange)
	{
		//this one is easy too: we create the thing that was deleted
		reversedChange.setType(Change.Type.CREATE);
		reversedChange.setName(change.getName());
	}
	
	/**
	 * Reverses a change of type == UPDATE
	 * 
	 * @param change The original change which is to be reversed
	 * @param reversedChange The reversed change
	 */
	private void reverseUpdate(Change change, Change reversedChange)
	{
		//this one is a little more tricky:
		//we also have to swap the old and new values
		reversedChange.setType(Change.Type.UPDATE);

		//whatever changed in the original change, will need to be changed too
		reversedChange.setWhatChanged(Change.WhatChanged.valueOf(change.getWhatChanged()));
		reversedChange.setNewValue(change.getOldValue());
		reversedChange.setOldValue(change.getNewValue());
	}

	/**
	 * Returns an ArrayList containing the reversed changes of the ones given as 
	 * an argument to the constructor
	 * 
	 * @return An ArrayList of{@link Change}s that contains the opposite changes of the ones 
	 * given as an argument
	 */
	public ArrayList<Change> getReversedChanges()
	{
		return this._reversedChanges;
	}

	/**
	 * The original changes that will be reversed
	 */
	private ArrayList<Change> _changes = new ArrayList();

	/**
	 * The reversed changes
	 */
	private ArrayList<Change> _reversedChanges = new ArrayList();

	/**
	 * Logger instance
	 */
	private static Logger log = Logger.getLogger(ReverseChange.class);
}
